/**
 * Created by rockyl on 2021/8/13.
 */
const isMacintosh = true

export interface Point {
  x: number
  y: number
}

export interface DeltaInfo {
  x: number
  y: number
  startX: number
  startY: number
  deltaX: number
  deltaY: number
  firstMove: boolean
  moved: boolean
}

export interface ProxyMouseMoveOptions {
  onMoveStart?: (info: DeltaInfo, e: MouseEvent) => void
  onMoveUpdate?: (info: DeltaInfo, e: MouseEvent) => void
  onMoveEnd?: (info: DeltaInfo, e: MouseEvent) => void
}

export function proxyMouseMove(mouseDownEvent: MouseEvent, options: ProxyMouseMoveOptions) {
  const {
    onMoveStart,
    onMoveUpdate,
    onMoveEnd,
  } = options

  let startMousePos: Point = {x: 0, y: 0}
  let firstMove = true
  let moved = false

  onMouseDown(mouseDownEvent)

  function onMouseDown(e: MouseEvent) {
    startMousePos.x = e.clientX
    startMousePos.y = e.clientY

    onMoveStart && onMoveStart({
      x: e.clientX,
      y: e.clientY,
      startX: startMousePos.x,
      startY: startMousePos.y,
      deltaX: 0,
      deltaY: 0,
      firstMove,
      moved,
    }, e)

    document.addEventListener('mousemove', onMouseMove)
    document.addEventListener('mouseup', onMouseUp)
  }

  function onMouseMove(e: MouseEvent) {
    moved = true
    const interrupt = onMoveUpdate && onMoveUpdate({
      x: e.clientX,
      y: e.clientY,
      startX: startMousePos.x,
      startY: startMousePos.y,
      deltaX: e.clientX - startMousePos.x,
      deltaY: e.clientY - startMousePos.y,
      firstMove,
      moved,
    }, e)
    if (interrupt) {
      document.removeEventListener('mousemove', onMouseMove)
      document.removeEventListener('mouseup', onMouseUp)
    }
    firstMove = false
  }

  function onMouseUp(e: MouseEvent) {
    document.removeEventListener('mousemove', onMouseMove)
    document.removeEventListener('mouseup', onMouseUp)

    onMoveEnd && onMoveEnd({
      x: e.clientX,
      y: e.clientY,
      startX: startMousePos.x,
      startY: startMousePos.y,
      deltaX: e.clientX - startMousePos.x,
      deltaY: e.clientY - startMousePos.y,
      firstMove,
      moved,
    }, e)
  }
}

export interface DragOptions {
  shouldDrag?: (e: MouseEvent) => boolean
  onDragStart?: () => void
  beforeDragMove?: (x: number, y: number) => Point
  onDragEnd?: () => void
}

export function startDrag(target: HTMLElement, e: MouseEvent, options: DragOptions = {}) {
  const {
    shouldDrag,
    onDragStart,
    beforeDragMove,
    onDragEnd,
  } = options

  let startPos: Point = {x: 0, y: 0}
  let startMousePos: Point = {x: 0, y: 0}

  onMouseDown(e)

  function onMouseDown(e: MouseEvent) {
    if (shouldDrag && !shouldDrag(e)) {
      return
    }

    startPos = {x: target.offsetLeft, y: target.offsetTop}
    startMousePos = {x: e.clientX, y: e.clientY}
    onDragStart && onDragStart()

    document.addEventListener('mousemove', onMouseMove)
    document.addEventListener('mouseup', onMouseUp)
  }

  function onMouseMove(e: MouseEvent) {
    const offX = e.clientX - startMousePos.x
    const offY = e.clientY - startMousePos.y
    const {x: sx, y: sy} = startPos
    let tx = sx + offX
    let ty = sy + offY
    if (beforeDragMove) {
      const ensurePos = beforeDragMove(tx, ty)
      if (ensurePos) {
        tx = ensurePos.x
        ty = ensurePos.y
      }
    }

    if (tx !== undefined) target.style.left = tx + 'px'
    if (ty !== undefined) target.style.top = ty + 'px'

  }

  function onMouseUp(e: MouseEvent) {
    document.removeEventListener('mousemove', onMouseMove)
    document.removeEventListener('mouseup', onMouseUp)

    onDragEnd && onDragEnd()
  }
}

/*

export interface GestureData {
    x?: number
    y?: number
    scale?: number
}

export interface GestureOptions {
    triggerTarget?: any
    applyResult: (data: GestureData) => void
}

export function useGesture(target, options: GestureOptions) {
    const {triggerTarget, applyResult} = options

    const trigger = triggerTarget || target
    trigger.on('mousewheel', e => {
        e.stop()
        //@ts-ignore
        const {ctrlKey, deltaX, deltaY} = e.event

        if (ctrlKey) {
            if (isMacintosh) {
                _gestureZoomHandler(e.event)
            } else {
                _mouseWheelHandler(e.event)
            }
        } else {
            if (deltaY % 1 == 0 && isMacintosh) {
                _gesturePanHandler(e.event)
            } else {
                _mouseWheelHandler(e.event)
            }
        }
    })


    function _gesturePanHandler(event) {
        const offsetX = event.deltaX / 2
        const offsetY = event.deltaY / 2
        const x = target.x - offsetX
        const y = target.y - offsetY

        applyResult({x, y})
    }

    function _gestureZoomHandler(event) {
        let delta = event.deltaY / 5
        delta = delta * (target.scaleX / 5)

        _applyZoom(event, delta)
    }

    function _mouseWheelHandler(event) {
        let delta = event.deltaY
        if (delta > 0) {
            delta = 1
        } else if (delta < 0) {
            delta = -1
        }
        delta = delta * (target.scaleX / 7)

        _applyZoom(event, delta)
    }

    function _applyZoom(event, delta) {
        const curScale = target.scaleX
        let targetScale = curScale - delta
        if (targetScale < 0.3) {
            targetScale = 0.3
        }
        if (targetScale > 5) {
            targetScale = 5
        }

        const offsetX = (event as any).layerX - target.x
        const offsetY = (event as any).layerY - target.y

        const newOffsetX = offsetX * targetScale / curScale
        const newOffsetY = offsetY * targetScale / curScale

        const x = target.x - (newOffsetX - offsetX)
        const y = target.y - (newOffsetY - offsetY)

        applyResult({x, y, scale: targetScale})
    }
}
*/
